package com.pai4j.pay.service;


import com.pai4j.common.bean.APIPageResponseBean;
import com.pai4j.common.constants.WebConstant;
import com.pai4j.common.enums.CommonStatusEnum;
import com.pai4j.common.enums.RedisKeyEnum;
import com.pai4j.common.service.RedisService;
import com.pai4j.common.util.AkSkGenerator;
import com.pai4j.common.util.JsonUtil;
import com.pai4j.domain.vo.dto.payment.AppAkSkDTO;
import com.pai4j.domain.vo.request.payment.CreateAppRequestVO;
import com.pai4j.domain.vo.response.payment.AppBaseResponseVO;
import com.pai4j.domain.vo.response.payment.CreateAppResponseVO;
import com.pai4j.pay.repository.dao.IAppDAO;
import com.pai4j.pay.repository.entity.AppEntity;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class PaymentAppService {

    @Autowired
    private IAppDAO appDAO;

    @Autowired
    private RedisService redisService;

    @Autowired
    private AccountService accountService;

    /**
     * 获取接入方访问凭证，走redis
     *
     * @param appId
     * @return
     */
    public AppAkSkDTO getAppAkSk(Long appId) {
        String akskCacheKey = RedisKeyEnum.PAYMENT_APP_AK_SK_CACHE.getKey();
        String cache = redisService.hget(akskCacheKey, String.valueOf(appId));
        if (StringUtils.isNotBlank(cache)) {
            return JsonUtil.fromJson(cache, AppAkSkDTO.class);
        }
        return this.refreshAppAkSkCache(appId);
    }

    /**
     * 查询应用详情信息，走redis
     *
     * @param appId
     * @return
     */
    public AppBaseResponseVO appInfo(Long appId) {
        String appCacheKey = this.appCacheKey(appId);
        String cache = redisService.get(appCacheKey);
        if (StringUtils.isNotBlank(cache)) {
            return JsonUtil.fromJson(cache, AppBaseResponseVO.class);
        }
        // 缓存防止击穿
        String defaultCache = redisService.get(defaultAppCacheKey(appId));
        if (ObjectUtils.equals(defaultCache, WebConstant.CACHE_NONE)) {
            return null;
        }
        AppBaseResponseVO appBase = this.refreshAppInfoCache(appId);
        if (appBase == null) {
            this.setDefaultAppCache(appId);
        }
        return appBase;
    }

    /**
     * 创建应用，接入支付平台
     *
     * @param createAppRequest
     * @return
     */
    public CreateAppResponseVO saveApp(CreateAppRequestVO createAppRequest) {
        /**
         * 1. 持久化：创建 Or 更新
         */
        boolean isFirstCreate = createAppRequest.getId() == null;
        AppEntity appEntity = convert(createAppRequest);
        String sk = null;
        if (isFirstCreate) {
            /**
             * 首次创建为应用生成支付凭证
             */
            String ak = AkSkGenerator.generateAk();
            sk = AkSkGenerator.generateSk();
            String secretHashKey = AkSkGenerator.hashKey(sk);
            appEntity.setAccessKey(ak);
            appEntity.setSecretHashKey(secretHashKey);
        }
        appEntity = appDAO.save(appEntity);
        /**
         * 2. 创建缓存
         */
        this.createOrUpdateRedisCache(appEntity);
        /**
         * 3. 构造应用信息页面响应VO
         */
        AppBaseResponseVO appBaseResponseVO = covertResponseVo(appEntity);;
        CreateAppResponseVO createAppResponseVO = new CreateAppResponseVO();
        BeanUtils.copyProperties(appBaseResponseVO, createAppResponseVO);
        createAppResponseVO.setSecretKey(sk);
        createAppResponseVO.setAdminInfo(accountService.accountInfo(appEntity.getAdmin()));
        return createAppResponseVO;
    }

    /**
     * 发布应用
     * @param appId
     */
    public void publishApp(Long appId) {

        this.updateAppStatus(appId, CommonStatusEnum.PUBLISHED);
    }

    /**
     * 删除应用
     * @param appId
     */
    public void deleteApp(Long appId) {

        this.updateAppStatus(appId, CommonStatusEnum.DELETED);
    }

    private void updateAppStatus(Long appId, CommonStatusEnum status) {
        AppEntity appEntity = appDAO.findById(appId).orElse(null);
        Assert.notNull(appEntity, "状态修改失败: 应用不存在");
        appEntity.setStatus(status.getStatusCode());
        appDAO.save(appEntity);
        // 刷新应用详情信息缓存
        this.refreshAppInfoCache(appEntity);
    }

    /**
     * 查询应用列表
     *
     * @param keywords
     * @param pageNo
     * @param pageSize
     * @return
     */
    public APIPageResponseBean<AppBaseResponseVO> page(String keywords, Integer pageNo, Integer pageSize) {

        Pageable pageable = PageRequest.of(pageNo - 1, pageSize, Sort.by(Sort.Direction.DESC, "id"));
        List<Integer> statusList = new ArrayList<>();
        statusList.add(CommonStatusEnum.NEW.getStatusCode());
        statusList.add(CommonStatusEnum.PUBLISHED.getStatusCode());

        Page<AppEntity> appEntities;
        if (StringUtils.isBlank(keywords)) {
            appEntities = appDAO.findAllByStatusIn(statusList, pageable);
        } else {
            appEntities = appDAO.findAllByNameLikeAndStatusIn("%" + keywords + "%", statusList, pageable);
        }
        List<AppBaseResponseVO> vos = new ArrayList<>();
        if (appEntities != null && CollectionUtils.isNotEmpty(appEntities.getContent())) {
            vos = appEntities.getContent().stream().map(this::covertResponseVo).collect(Collectors.toList());
        }
        return APIPageResponseBean.success(pageNo, pageSize, appEntities.getTotalElements(), vos);
    }

    private AppBaseResponseVO covertResponseVo(AppEntity appEntity) {
        AppBaseResponseVO response = new AppBaseResponseVO();
        BeanUtils.copyProperties(appEntity, response);
        return response;
    }

    /**
     * 创建或者更新应用信息Redis缓存
     */
    private void createOrUpdateRedisCache(AppEntity appEntity) {

        // 1. 刷新应用最新详情缓存
        this.refreshAppInfoCache(appEntity);

        // 2. 创建或更新AK-SK缓存
        this.refreshAppAkSkCache(appEntity.getId(), appEntity.getAccessKey(), appEntity.getSecretHashKey());
    }


    /**
     * 刷新应用访问支付平台凭证缓存
     *
     * @param appId
     * @return
     */
    private AppAkSkDTO refreshAppAkSkCache(Long appId) {

        AppEntity app = appDAO.findById(appId).orElse(null);
        return this.refreshAppAkSkCache(app.getId(), app.getAccessKey(), app.getSecretHashKey());
    }

    private AppAkSkDTO refreshAppAkSkCache(Long appId, String accessKey, String secretHashKey) {
        String akskCacheKey = RedisKeyEnum.PAYMENT_APP_AK_SK_CACHE.getKey();
        AppAkSkDTO appAkSkDTO = new AppAkSkDTO(accessKey, secretHashKey);
        redisService.hset(akskCacheKey,
                String.valueOf(appId), JsonUtil.toJsonString(appAkSkDTO),
                RedisKeyEnum.PAYMENT_APP_AK_SK_CACHE.getExpireTime());
        return appAkSkDTO;
    }

    private void setDefaultAppCache(Long appId) {
        String defaultKey = this.defaultAppCacheKey(appId);
        redisService.set(defaultKey, WebConstant.CACHE_NONE, RedisKeyEnum.PAYMENT_DEFAULT_APP_INFO_CACHE.getExpireTime());
    }

    private AppBaseResponseVO refreshAppInfoCache(Long appId) {
        AppEntity appEntity = appDAO.findById(appId).orElse(null);
        return this.refreshAppInfoCache(appEntity);
    }

    /**
     * 刷新应用信息详情缓存
     *
     * @param appEntity
     * @return
     */
    private AppBaseResponseVO refreshAppInfoCache(AppEntity appEntity) {
        if (appEntity == null) {
            return null;
        }
        AppBaseResponseVO appBaseResponseVO = this.covertResponseVo(appEntity);
        String appCacheKey = this.appCacheKey(appEntity.getId());
        redisService.set(appCacheKey, JsonUtil.toJsonString(appBaseResponseVO),
                RedisKeyEnum.PAYMENT_APP_INFO_CACHE.getExpireTime());
        return appBaseResponseVO;
    }

    private String defaultAppCacheKey(Long appId) {
        return RedisKeyEnum.PAYMENT_DEFAULT_APP_INFO_CACHE.getKey(String.valueOf(appId));
    }

    private String appCacheKey(Long appId) {
        return RedisKeyEnum.PAYMENT_APP_INFO_CACHE.getKey(String.valueOf(appId));
    }

    private AppEntity convert(CreateAppRequestVO createAppRequest) {
        AppEntity appEntity;
        if (createAppRequest.getId() != null) {
            appEntity = appDAO.findById(createAppRequest.getId()).orElse(null);
            Assert.notNull(appEntity, "应用信息更新失败：应用不存在！");
        } else {
            appEntity = new AppEntity();
            appEntity.setAdmin(createAppRequest.getUserId());
            appEntity.setCreateBy(createAppRequest.getUserId());
            // 后面改成默认新建状态
            appEntity.setStatus(CommonStatusEnum.NEW.getStatusCode());
        }
        appEntity.setLogo(createAppRequest.getLogo());
        appEntity.setName(createAppRequest.getName());
        appEntity.setDescription(createAppRequest.getDescription());
        appEntity.setUpdateBy(createAppRequest.getUserId());
        appEntity.setCallBack(createAppRequest.getCallBack());
        appEntity.setCallBackPage(createAppRequest.getCallBackPage());
        return appEntity;
    }
}
